package com.pony.iphone.utils.ding;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.pony.iphone.utils.ding.pojo.*;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.format.DateTimeFormatter;
import java.util.Base64;

/**
 * @author pony
 * 钉钉机器人发消息工具类
 */
@Slf4j
@Component
public class DingTalkUtil {

    // 钉钉机器人的WebHook Token
    @Value("${dingtalk.webhook-token:bc89455d31d2c0024c90047dc6e6a443a9d29e20d53080fd2406b18cb14a4059}")
    private String webhookToken;

    // 钉钉机器人的加签（密钥）需要进行处理
    @Value("${dingtalk.secret:SEC0b621f746b0a30280f464d4a8daf2978e9c0d9f57dd07ac08eec3f5bb071e93e}")
    private String secret;

    /**
     * 初始化，主要是检查一下参数
     */
    @PostConstruct
    public void init() {
        log.info("=== 钉钉配置初始化 ===");
        log.info("webhookToken: {}", webhookToken != null ? webhookToken.substring(0, 10) + "..." : "null");
        log.info("secret: {}", secret != null ? secret.substring(0, 10) + "..." : "null");

        if (secret == null || webhookToken == null) {
            log.error("钉钉配置未正确注入，请检查配置文件");
        } else {
            log.info("钉钉工具初始化完成");
        }
        log.info("===================");
    }

    /**
     * 创建消息建造者
     */
    public DingTalkMessageBuilder buildMessage() {
        return new DingTalkMessageBuilder(this);
    }

    /**
     * 快速发送普通文本消息
     * @param content 消息的内容
     * @return 发送结果，打印钉钉官方接口的返回结果
     */
    public boolean sendText(String content) {
        return buildMessage().text(content).send();
    }

    /**
     * 快速发送错误消息
     * @param errorMessage 错误的消息的内容
     * @return 发送结果，打印钉钉官方接口的返回结果
     */
    public boolean sendError(String errorMessage) {
        String formattedMessage = String.format("【错误警报】题库管理系统\n错误信息: %s\n时间: %s",
                errorMessage, java.time.LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        return buildMessage().text(formattedMessage).send();
    }

    /**
     * 快速发送Markdown消息
     * @param title 标题
     * @param content 内容
     * @return 发送结果，打印钉钉官方接口的返回结果
     */
    public boolean sendMarkdown(String title, String content) {
        return buildMessage().markdown(title, content).send();
    }

    /**
     * 发送消息核心方法
     * @param builder 消息建造者，确定消息的类型
     * @return 发送结果，打印钉钉官方接口的返回结果
     */
    public boolean sendMessage(DingTalkMessageBuilder builder) {
        if (builder.getMessageBody() == null) {
            log.warn("钉钉消息内容为空，跳过发送");
            return false;
        }

        // 检查配置
        if (secret == null || webhookToken == null) {
            log.error("钉钉配置未初始化，无法发送消息");
            return false;
        }

        try {
            String jsonPayload = buildJsonPayload(builder);
            return sendHttpRequest(jsonPayload);
        } catch (Exception e) {
            log.error("发送钉钉消息异常", e);
            return false;
        }
    }

    /**
     * 构建JSON负载
     */
    private String buildJsonPayload(DingTalkMessageBuilder builder) {
        ObjectMapper mapper = new ObjectMapper();
        ObjectNode payload = mapper.createObjectNode();

        // 设置消息类型和内容
        switch (builder.getMsgType()) {
            case TEXT:
                DingTalkText text = (DingTalkText) builder.getMessageBody();
                payload.put("msgtype", "text");
                ObjectNode textNode = mapper.createObjectNode();
                textNode.put("content", text.getContent());
                payload.set("text", textNode);
                break;

            case LINK:
                DingTalkLink link = (DingTalkLink) builder.getMessageBody();
                payload.put("msgtype", "link");
                ObjectNode linkNode = mapper.createObjectNode();
                linkNode.put("title", link.getTitle());
                linkNode.put("text", link.getText());
                linkNode.put("messageUrl", link.getMessageUrl());
                if (link.getPicUrl() != null) {
                    linkNode.put("picUrl", link.getPicUrl());
                }
                payload.set("link", linkNode);
                break;

            case MARKDOWN:
                DingTalkMarkdown markdown = (DingTalkMarkdown) builder.getMessageBody();
                payload.put("msgtype", "markdown");
                ObjectNode markdownNode = mapper.createObjectNode();
                markdownNode.put("title", markdown.getTitle());
                markdownNode.put("text", markdown.getText());
                payload.set("markdown", markdownNode);
                break;

            case ACTION_CARD:
                DingTalkActionCard actionCard = (DingTalkActionCard) builder.getMessageBody();
                payload.put("msgtype", "actionCard");
                ObjectNode actionCardNode = mapper.createObjectNode();
                actionCardNode.put("title", actionCard.getTitle());
                actionCardNode.put("text", actionCard.getText());

                if (actionCard.getSingleTitle() != null && actionCard.getSingleURL() != null) {
                    actionCardNode.put("singleTitle", actionCard.getSingleTitle());
                    actionCardNode.put("singleURL", actionCard.getSingleURL());
                }

                if (actionCard.getBtns() != null && !actionCard.getBtns().isEmpty()) {
                    ArrayNode buttonsNode = mapper.createArrayNode();
                    for (DingTalkActionCard.Button btn : actionCard.getBtns()) {
                        ObjectNode btnNode = mapper.createObjectNode();
                        btnNode.put("title", btn.getTitle());
                        btnNode.put("actionURL", btn.getActionURL());
                        buttonsNode.add(btnNode);
                    }
                    actionCardNode.set("btns", buttonsNode);
                }

                if (actionCard.getBtnOrientation() != null) {
                    actionCardNode.put("btnOrientation", actionCard.getBtnOrientation());
                }

                payload.set("actionCard", actionCardNode);
                break;

            case FEED_CARD:
                DingTalkFeedCard feedCard = (DingTalkFeedCard) builder.getMessageBody();
                payload.put("msgtype", "feedCard");
                ArrayNode linksNode = mapper.createArrayNode();
                for (DingTalkFeedCard.Link linkItem : feedCard.getLinks()) {
                    ObjectNode linkItemNode = mapper.createObjectNode();
                    linkItemNode.put("title", linkItem.getTitle());
                    linkItemNode.put("messageURL", linkItem.getMessageURL());
                    linkItemNode.put("picURL", linkItem.getPicURL());
                    linksNode.add(linkItemNode);
                }
                ObjectNode feedCardNode = mapper.createObjectNode();
                feedCardNode.set("links", linksNode);
                payload.set("feedCard", feedCardNode);
                break;
        }

        // 设置@信息
        if (builder.getAt() != null) {
            DingTalkAt at = builder.getAt();
            ObjectNode atNode = mapper.createObjectNode();

            if (at.getIsAtAll() != null) {
                atNode.put("isAtAll", at.getIsAtAll());
            }

            if (at.getAtMobiles() != null && !at.getAtMobiles().isEmpty()) {
                ArrayNode mobilesNode = mapper.valueToTree(at.getAtMobiles());
                atNode.set("atMobiles", mobilesNode);
            }

            if (at.getAtUserIds() != null && !at.getAtUserIds().isEmpty()) {
                ArrayNode userIdsNode = mapper.valueToTree(at.getAtUserIds());
                atNode.set("atUserIds", userIdsNode);
            }

            payload.set("at", atNode);
        }

        return payload.toString();
    }

    /**
     * 发送HTTP请求
     */
    private boolean sendHttpRequest(String jsonPayload) throws Exception {
        long timestamp = System.currentTimeMillis();
        String stringToSign = timestamp + "\n" + secret;
        String sign = generateSign(stringToSign);

        String webhookUrl = String.format(
                "https://oapi.dingtalk.com/robot/send?access_token=%s&timestamp=%d&sign=%s",
                webhookToken, timestamp, sign
        );

        log.info("请求URL: https://oapi.dingtalk.com/robot/send?access_token=***&timestamp={}&sign={}", timestamp, sign);
        log.info("请求体JSON: {}", jsonPayload);

        URL url = new URL(webhookUrl);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
        conn.setDoOutput(true);
        conn.setConnectTimeout(10000);
        conn.setReadTimeout(10000);

        try (OutputStream os = conn.getOutputStream()) {
            os.write(jsonPayload.getBytes(StandardCharsets.UTF_8));
            os.flush();
        }

        int responseCode = conn.getResponseCode();
        log.debug("HTTP响应码: {}", responseCode);

        if (responseCode == 200) {
            try (java.io.InputStream is = conn.getInputStream()) {
                String responseBody = new String(is.readAllBytes(), StandardCharsets.UTF_8);
                log.debug("钉钉API响应: {}", responseBody);

                if (responseBody.contains("\"errcode\":0")) {
                    log.info("✅ 钉钉消息发送成功");
                    return true;
                } else {
                    log.error("❌ 钉钉API返回错误: {}", responseBody);
                    return false;
                }
            }
        } else {
            try (java.io.InputStream es = conn.getErrorStream()) {
                String responseBody = es != null ?
                        new String(es.readAllBytes(), StandardCharsets.UTF_8) : "无错误信息";
                log.error("钉钉消息发送失败，响应码: {}, 错误信息: {}", responseCode, responseBody);
                return false;
            }
        }
    }

    /**
     * 生成HMAC-SHA256签名
     */
    private String generateSign(String stringToSign) {
        try {
            String actualSecret = secret;
            Mac mac = Mac.getInstance("HmacSHA256");
            SecretKeySpec spec = new SecretKeySpec(actualSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            mac.init(spec);

            byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
            String base64Sign = Base64.getEncoder().encodeToString(signData);
            return URLEncoder.encode(base64Sign, StandardCharsets.UTF_8);

        } catch (Exception e) {
            log.error("生成钉钉签名失败", e);
            throw new RuntimeException("生成钉钉签名失败", e);
        }
    }

    /**
     * 测试方法
     */
    public void testConnection() {
        log.info("=== 开始钉钉连接测试 ===");

        // 测试文本消息
        buildMessage().text("钉钉连接测试消息 - " + java.time.LocalDateTime.now()).send();

        // 测试Markdown消息
        buildMessage().markdown("测试标题", "### 这是Markdown消息\n- 项目1\n- 项目2").send();

        // 测试链接消息
        buildMessage().link("测试链接", "这是一个链接消息", "https://www.example.com").send();

        log.info("=== 钉钉连接测试结束 ===");
    }
}